#pragma once

#include <iostream>
/// 32-bit hash value for a string.
class  StringHash
{
public:
	/// Construct with zero value.
	StringHash() noexcept :
		value_(0)
	{
	}

	/// Copy-construct from another hash.
	StringHash(const StringHash& rhs) noexcept = default;

	/// Construct with an initial value.
	explicit StringHash(unsigned value) noexcept :
		value_(value)
	{
	}

	/// Construct from a C string.
	StringHash(const char* str) noexcept;        // NOLINT(google-explicit-constructor)
	/// Construct from a string.
	StringHash(const std::string& str) noexcept;      // NOLINT(google-explicit-constructor)

	/// Assign from another hash.
	StringHash& operator =(const StringHash& rhs) noexcept = default;

	/// Add a hash.
	StringHash operator +(const StringHash& rhs) const
	{
		StringHash ret;
		ret.value_ = value_ + rhs.value_;
		return ret;
	}

	/// Add-assign a hash.
	StringHash& operator +=(const StringHash& rhs)
	{
		value_ += rhs.value_;
		return *this;
	}

	/// Test for equality with another hash.
	bool operator ==(const StringHash& rhs) const { return value_ == rhs.value_; }

	/// Test for inequality with another hash.
	bool operator !=(const StringHash& rhs) const { return value_ != rhs.value_; }

	/// Test if less than another hash.
	bool operator <(const StringHash& rhs) const { return value_ < rhs.value_; }

	/// Test if greater than another hash.
	bool operator >(const StringHash& rhs) const { return value_ > rhs.value_; }

	/// Return true if nonzero hash value.
	explicit operator bool() const { return value_ != 0; }

	/// Return hash value.
	/// @property
	unsigned Value() const { return value_; }

	/// Return as string.
	std::string ToString() const;

	/// Return hash value for HashSet & HashMap.
	unsigned ToHash() const { return value_; }

	/// Calculate hash value from a C string.
	static unsigned Calculate(const char* str, unsigned hash = 0);

	/// Zero hash.
	static const StringHash ZERO;

private:
	/// Hash value.
	unsigned value_;
};

